/**
 * Ext.grid.PropertyGrid
 * @override initComponnet to prevent clicks on Property-name field from initiating a value-cell-edit
 * @author Chris Scott
 */
Ext.override(Ext.grid.PropertyGrid, {

    /**
     * @cfg {Boolean} ignoreNameCellClick true to prevent clicks on name-cell from initiating value-cell editing.
     */
    ignoreNameCellClick : false,

    // private
    initComponent : function(){
        this.customEditors = this.customEditors || {};
        this.lastEditRow = null;
        var store = new Ext.grid.PropertyStore(this);
        this.propStore = store;
        var cm = new Ext.grid.PropertyColumnModel(this, store);

        // disable sort for schema grid.  index is important here.
        //store.store.sort('name', 'ASC');

        this.addEvents(
            /**
             * @event beforepropertychange
             * Fires before a property value changes.  Handlers can return false to cancel the property change
             * (this will internally call {@link Ext.data.Record#reject} on the property's record).
             * @param {Object} source The source data object for the grid (corresponds to the same object passed in
             * as the {@link #source} config property).
             * @param {String} recordId The record's id in the data store
             * @param {Mixed} value The current edited property value
             * @param {Mixed} oldValue The original property value prior to editing
             */
            'beforepropertychange',
            /**
             * @event propertychange
             * Fires after a property value has changed.
             * @param {Object} source The source data object for the grid (corresponds to the same object passed in
             * as the {@link #source} config property).
             * @param {String} recordId The record's id in the data store
             * @param {Mixed} value The current edited property value
             * @param {Mixed} oldValue The original property value prior to editing
             */
            'propertychange'
        );
        this.cm = cm;
        this.ds = store.store;
        Ext.grid.PropertyGrid.superclass.initComponent.call(this);

        // reason for override is here.  only initiate cell edits on name-cell clicks if ignore is false.
        this.selModel.on('beforecellselect', this.onCellClick, this);

    },

    onCellClick : function(sm, rIndex, cIndex) {
        this.stopEditing();
        if (this.ignoreNameCellClick === false && colIndex === 0) {
            this.startEditing.defer(200, this, [rowIndex, 1]);
            return false;
        }
    }
});

/**
 * RExt.grid.SchemaGrid
 * @author Chris Scoot
 */
RExt.grid.SchemaGrid = Ext.extend(Ext.grid.PropertyGrid, {
    ignoreNameCellClick: true,

    initComponent : function() {
        this.on('render', function(g) {
            this.initDraggables(g);
            this.initDroppables(g);
        }, this);

        RExt.grid.SchemaGrid.superclass.initComponent.call(this);

    },

    initDraggables : function(grid) {
        grid.dragZone = new Ext.dd.DragZone(grid.getEl(), {
            // On receipt of a mousedown event, see if it is within a draggable element.
            // Return a drag data object if so. The data object can contain arbitrary application
            // data, but it should also contain a DOM element in the ddel property to provide
            // a proxy to drag.
            getDragData: function(e) {

                var sourceEl = e.getTarget('.x-grid3-col-name', 2);
                if (sourceEl) {
                    d = sourceEl.cloneNode(true);
                    d.id = Ext.id();
                    return grid.dragData = {
                        sourceEl: sourceEl,
                        repairXY: Ext.fly(sourceEl).getXY(),
                        ddel: d,
                        record: grid.store.getAt(grid.getView().findRowIndex(sourceEl))
                    }
                }
            },

            // Provide coordinates for the proxy to slide back to on failed drag.
            // This is the original XY coordinates of the draggable element.
            getRepairXY: function() {
                return this.dragData.repairXY;
            }
        });
    },

    /*
     * Here is where we "activate" the GridPanel.
     * We have decided that the element with class "hospital-target" is the element which can receieve
     * drop gestures. So we inject a method "getTargetFromEvent" into the DropZone. This is constantly called
     * while the mouse is moving over the DropZone, and it returns the target DOM element if it detects that
     * the mouse if over an element which can receieve drop gestures.
     *
     * Once the DropZone has been informed by getTargetFromEvent that it is over a target, it will then
     * call several "onNodeXXXX" methods at various points. These include:
     *
     * onNodeEnter
     * onNodeOut
     * onNodeOver
     * onNodeDrop
     *
     * We provide implementations of each of these to provide behaviour for these events.
     */
    initDroppables : function(g) {
        g.dropZone = new Ext.dd.DropZone(g.getView().scroller, {

            // If the mouse is over a target node, return that node. This is
            // provided as the "target" parameter in all "onNodeXXXX" node event handling functions
            getTargetFromEvent: function(e) {
                return e.getTarget('.x-grid3-row');
            },

            // On entry into a target node, highlight that node.
            onNodeEnter : function(target, dd, e, data){
                Ext.fly(target).addClass('r-schema-grid-dropzone');
            },

            // On exit from a target node, unhighlight that node.
            onNodeOut : function(target, dd, e, data){
                Ext.fly(target).removeClass('r-schema-grid-dropzone');
            },

            // While over a target node, return the default drop allowed class which
            // places a "tick" icon into the drag proxy.
            onNodeOver : function(target, dd, e, data){
                return Ext.dd.DropZone.prototype.dropAllowed;
            },

            // On node drop, we can interrogate the target node to find the underlying
            // application object that is the real target of the dragged data.
            // In this case, it is a Record in the GridPanel's Store.
            // We can use the data set up by the DragZone's getDragData method to read
            // any data we decided to attach.
            onNodeDrop : function(target, dd, e, data) {
                App.setAlert(App.STATUS_INFO, 'onNodeDrop');
                var view = g.getView();
                g.store.remove(data.record);
                var rIndex = view.findRowIndex(target);
                if (rIndex < 0) {
                    rIndex = 0;
                }
                g.store.insert(rIndex, data.record);
                g.getSelectionModel().select(rIndex, 0);

            }
        });
    }
});

